#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////

LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
ls(nomFich), ts() {
}


////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
    try {
        accFichier aF;
        aF.ouvrirF();
        arbre = programme();
        arbre->transcod(&aF);
        aF.fermerF();
        cout << "Syntaxe correcte." << endl; //ici on va try catch les erreurs
    } catch (Exception1 Ex1) {
        cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
                << ls.getColonne() << endl << "   Attendu : " << Ex1.message << endl
                << "   Trouve  : " << ls.getSymCour() << endl << endl;
    }
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::programme() {
    // <programme> ::= debut <seq_inst> fin FIN_FICHIER

    sauterSymCour("debut");
    Noeud* si = seqInst();
    sauterSymCour("fin");
    testerSymCour("<FINDEFICHIER>");
    return si;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::seqInst() {
    // <seqInst> ::= <inst> ; { <inst> ; }

    NoeudSeqInst* si = new NoeudSeqInst();
    do {
	si->ajouteInstruction(inst());
	sauterSymCour(";");
    } while (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "si" || ls.getSymCour() == "tantque" || ls.getSymCour() == "repeter" || ls.getSymCour() == "pour" || ls.getSymCour() == "choix");
    // tant que le symbole courant est un debut possible d'instruction...
    return si;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::inst() {
    // <inst> ::=  <affectation> | <instSi> | <instTq> | <instRepeter>

    if (ls.getSymCour() == "si") {
	return instSi();
    } else if (ls.getSymCour() == "tantque") {
	return instTq();
    } else if (ls.getSymCour() == "repeter") {
	return instRepeter();
    } else if (ls.getSymCour() == "pour") {
	return instPour();
    } else if (ls.getSymCour() == "lire") {
	return instLire();
    } else if (ls.getSymCour() == "ecrire") {
	return instEcrire();
    } else if (ls.getSymCour() == "choix") {
	return choix();
    } else {
	return affectation();
    }
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::affectation() {
    // <affectation> ::= <variable> = <expression>

    testerSymCour("<VARIABLE>");
    Noeud* var = ts.chercheAjoute(ls.getSymCour());
    ls.suivant();
    sauterSymCour("=");
    Noeud* exp = expression();
    return new NoeudAffectation(var, exp);
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::expression() {
    // <expression> ::= <facteur> { <opBinaire> <facteur> }

    Noeud* fact = facteur();
    while (ls.getSymCour() == "+" || ls.getSymCour() == "-" ||
	    ls.getSymCour() == "*" || ls.getSymCour() == "/") {
	Symbole operateur = opBinaire(); // on stocke le symbole de l'opÃ©rateur
	Noeud* factDroit = facteur(); // lecture de l'operande droit
	fact = new NoeudOperateurBinaire(operateur, fact, factDroit); // const. du noeud
    }
    return fact;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::facteur() {
    // <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )

    Noeud* fact = NULL;

    if (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "<ENTIER>" || ls.getSymCour() == "<CHAINE>" ||ls.getSymCour() == "<REEL>" ) {
	fact = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
    } else if (ls.getSymCour() == "-" || ls.getSymCour() == "non") {
	fact = opUnaire();//?????
	fact = expBool();//??????
	// on reprÃ©sente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
	//fact = new NoeudOperateurBinaire(Symbole("-"), ts.chercheAjoute(Symbole("0")), facteur());
    } else if (ls.getSymCour() == "(") {
	ls.suivant();
	fact = expBool();
	sauterSymCour(")");
    } else
	erreur("<facteur>");
    return fact;
}

////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opBinaire() {
    // <opBinaire> ::= + | - | *  | /
    Symbole operateur;
    if (ls.getSymCour() == "+" || ls.getSymCour() == "-" ||
	    ls.getSymCour() == "*" || ls.getSymCour() == "/") {
	operateur = ls.getSymCour();
	ls.suivant();
    } else
	erreur("<opBinaire>");
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecArbre::testerSymCour(string ch) {
    if (ls.getSymCour() != ch) {
	/*cout << endl << "-------- Erreur ligne " << ls.getLigne()
		<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
		<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
		<< endl;
	exit(0); // plus tard, on levera une exception
	 */
	erreur(ch);
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
    testerSymCour(ch);
    ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecArbre::erreur(string mess) {
    /*cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
	    << ls.getColonne() << endl << "   Attendu : " << mess << endl
	    << "   Trouve  : " << ls.getSymCour() << endl << endl;
    exit(0); // plus tard, on levera une exception
     */
    Exception1 Ex1(mess);
    throw Ex1;
}

Noeud * LecteurPhraseAvecArbre::instSi() {
    //  <instSi>  ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> [ sinon <seqInst> ] finsi 
    NoeudSi * si;
    si = new NoeudSi();
    if (ls.getSymCour() == "si") {
	sauterSymCour("si");
	sauterSymCour("(");
	si->addC(expBool());
	sauterSymCour(")");
	sauterSymCour("alors");
	si->addI(seqInst());
	while (ls.getSymCour() == "sinonsi") {
	    sauterSymCour("sinonsi");
	    sauterSymCour("(");
	    si->addC(expBool());
	    sauterSymCour(")");
	    sauterSymCour("alors");
	    si->addI(seqInst());
	}
	if (ls.getSymCour() == "sinon") {
	    ls.suivant();
	    si->addS(seqInst());
	} else si->addS(NULL);
	sauterSymCour("finsi");
    }
    return si;
}

Noeud * LecteurPhraseAvecArbre::instPour() {
    // <instPour> ::= pour ( <affectation> ; <expBool> ; <affectation> ) <seqInst> finpour
    Noeud *fact1, *fact2, *fact3, *fact4;
    if (ls.getSymCour() == "pour") {
	sauterSymCour("pour");
	sauterSymCour("(");
	fact1 = affectation();
	sauterSymCour(";");
	fact2 = expBool();
	sauterSymCour(";");
	fact3 = affectation();
	sauterSymCour(")");
	fact4 = seqInst();
	sauterSymCour("finpour");
	return (new NoeudPour(fact1, fact2, fact3, fact4));

    }
    return (NULL);
}

////////////////////////////////////////////////////////////////////////////////

Noeud * LecteurPhraseAvecArbre::instTq() {
    // <instTq>  ::= tantque ( <expBool> ) <seqInst> fintantque
    Noeud *fact1, *fact2;
    if (ls.getSymCour() == "tantque") {
	sauterSymCour("tantque");
	sauterSymCour("(");
	fact1 = expBool();
	sauterSymCour(")");
	fact2 = seqInst();
	sauterSymCour("fintantque");
	return (new NoeudBoucle(fact1, fact2));
    } else return (NULL);
}

Noeud * LecteurPhraseAvecArbre::instRepeter() {
    // <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
    Noeud *fact1, *fact2;
    if (ls.getSymCour() == "repeter") {
	sauterSymCour("repeter");
	fact2 = seqInst();
	sauterSymCour("jusqua");
	sauterSymCour("(");
	fact1 = expBool();
	sauterSymCour(")");
	return (new NoeudRepeterJsqa(fact1, fact2, fact2));
    } else return (NULL);
}

Noeud * LecteurPhraseAvecArbre::instLire() {
    // <instLire> ::= lire ( <VARIABLE> )
    NoeudLire * lire = NULL;
    if (ls.getSymCour() == "lire") {
	sauterSymCour("lire");
	sauterSymCour("(");
	lire = new NoeudLire(ls.getSymCour());
	sauterSymCour("<VARIABLE>");
	sauterSymCour(")");
    }
    return lire;
}

Noeud * LecteurPhraseAvecArbre::instEcrire() {
    // <instEcrire> ::= ecrire ( <CHAINE> | <expression> )
    Noeud * ecrire = NULL;
    NoeudChaine * chaine = NULL;
    if (ls.getSymCour() == "ecrire") {
	sauterSymCour("ecrire");
	sauterSymCour("(");
	if (ls.getSymCour() == "<CHAINE>") {
	    chaine = new NoeudChaine(ls.getSymCour());
	    sauterSymCour("<CHAINE>");            
	} else {
	    ecrire = expression();     
	}
	sauterSymCour(")");
    }
    return ecrire;
}

////////////////////////////////////////////////////////////////////////////////

Noeud * LecteurPhraseAvecArbre::terme() {
    // <terme> ::= { <opMult> <facteur> }
    Noeud* fact;
    fact = facteur();
    while (ls.getSymCour() == "*" || ls.getSymCour() == "/") {
	Symbole operateur = opMult();
	Noeud* factDroit = facteur();
	fact = new NoeudOperateurBinaire(operateur, fact, factDroit);
    }
    return fact;
}

////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opAdd() {
    //<opAdd> ::= + | -
    Symbole symbole = ls.getSymCour();
    if (ls.getSymCour() == "+" || ls.getSymCour() == "-")
	ls.suivant();
    else {
	erreur("<opAdd>");
    }
    return (symbole);
}

////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opMult() {
    //<opMult> ::= * | /
    Symbole symbole = ls.getSymCour();
    if (ls.getSymCour() == "*" || ls.getSymCour() == "/") {

	ls.suivant();
    } else {
	erreur("<opMult>");
    }
    return (symbole);
}

////////////////////////////////////////////////////////////////////////////////

Noeud * LecteurPhraseAvecArbre::expBool() {
    // <expBool> ::= <expBoolOu>
    return (expBoolOu());

}

Noeud * LecteurPhraseAvecArbre::expBoolEt() {
    //<expBoolEt> ::= <Relation> { et <Relation> }

    Noeud * fact;
    fact = relation();
    while (ls.getSymCour() == "et") {
	sauterSymCour("et");
	Noeud* factDroit = relation();
	fact = new NoeudOperateurBinaire(Symbole("et"), fact, factDroit);
    }
    return (fact);
}

Noeud * LecteurPhraseAvecArbre::expBoolOu() {
    //<expBoolOu> ::= <expBoolEt> { ou <expBoolEt> }
    Noeud * fact;
    fact = expBoolEt();
    while (ls.getSymCour() == "ou") {
	sauterSymCour("ou");
	Noeud* factDroit = expBoolEt();
	fact = new NoeudOperateurBinaire(Symbole("ou"), fact, factDroit);
    }
    return (fact);
}

Noeud * LecteurPhraseAvecArbre::relation() {
    // <relation>::= <expression> { <opRel> <expression> }
    Noeud * fact;
    fact = expression();
    while (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<=" || ls.getSymCour() == ">=" || ls.getSymCour() == "<" || ls.getSymCour() == ">") {
	Symbole symbole = opRel();
	Noeud * factdroit = expression();
	fact = new NoeudOperateurBinaire(symbole, fact, factdroit);
    }
    return (fact);
}

////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opRel() {
    // <opRel> ::= == | != | > | >= | < | <=
    Symbole symbole = ls.getSymCour();
    if (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<=" || ls.getSymCour() == ">=" || ls.getSymCour() == "<" || ls.getSymCour() == ">") {
	ls.suivant();
    } else {
	erreur("<opRel>");
    }
    return (symbole);
}

////////////////////////////////////////////////////////////////////////////////

Noeud * LecteurPhraseAvecArbre::opUnaire() {
    // <opUnaire> ::= - | non
    if (ls.getSymCour() == "-") {
	return (new NoeudOperateurBinaire(Symbole("-"), ts.chercheAjoute(Symbole("0")), expBool()));
	ls.suivant();
    } else if (ls.getSymCour() == "non") {
	return (new NoeudOperateurBinaire(Symbole("non"), NULL, expBool()));
	ls.suivant();
    } else
	erreur("<opUnaire>");
}

Noeud * LecteurPhraseAvecArbre::choix() {
    NoeudSi * si;
    si = new NoeudSi();
    Symbole test;
    Symbole var;
    Noeud* testV;
    Noeud* varV;
    Noeud * fact;
    Noeud * factOp;

    sauterSymCour("choix");
    sauterSymCour("(");
    if (ls.getSymCour() == "<VARIABLE>") {
	var = ls.getSymCour();
	varV = ts.chercheAjoute(var);
	sauterSymCour("<VARIABLE>");
    } else {
	erreur("<VARIABLE>");
    }
    sauterSymCour(")");
    while (ls.getSymCour() == "cas") {
	sauterSymCour("cas");
	test = ls.getSymCour();
	testV = ts.chercheAjoute(test);
	sauterSymCour(ls.getSymCour().getChaine());
	fact = seqInst();
	si->addI(fact);
	factOp = new NoeudOperateurBinaire(Symbole("=="), varV, testV);
	si->addC(factOp);
	sauterSymCour("fincas"); //si on veut que fincas soit obligatoire
	//si on veut que fincas soit pas obligatoire
	//                if (ls.getSymCour() == "fincas") {
	//                    ls.suivant();
    }
    sauterSymCour("defaut");
    fact = seqInst();
    si->addS(fact);
    sauterSymCour("finchoix");
    return (si);
}
